#include <winsock2.h>
#include "packge_handler.h"
#include "packge_header.h"


QTreeWidgetItem* get_tree_item(QString q){
    return new QTreeWidgetItem(QStringList()<<q);
}
QString format_ip(u_char ip[4]){
    return QString("%1.%2.%3.%4").arg(ip[0]).arg(ip[1]).arg(ip[2]).arg(ip[3]);
}
QString format_mac(u_char mac[6]){

    if(mac[0]==0xff&&mac[1]==0xff&&mac[2]==0xff&&mac[3]==0xff&&mac[4]==0xff&&mac[5]==0xff){
        return "Broadcast";
    }

    return QString("%1:%2:%3:%4:%5:%6")
            .arg(mac[0],2,16,QLatin1Char('0'))
            .arg(mac[1],2,16,QLatin1Char('0'))
            .arg(mac[2],2,16,QLatin1Char('0'))
            .arg(mac[3],2,16,QLatin1Char('0'))
            .arg(mac[4],2,16,QLatin1Char('0'))
            .arg(mac[5],2,16,QLatin1Char('0'));
}
QString format_eth_type(u_short type){
    switch (type) {
    case 0x0800:	return "IPv4";break;
    case 0x0806:	return "ARP";break;
    case 0x0842:	return "Wake-on-LAN";break;
    case 0x22F0:	return "AVTP";break;
    case 0x22F3:	return "IETF TRILL Protocol";break;
    case 0x22EA:	return "Stream Reservation Protocol";break;
    case 0x6002:	return "DEC MOP RC";break;
    case 0x6003:	return "DECnet Phase IV, DNA Routing";break;
    case 0x6004:	return "DEC LAT";break;
    case 0x8035:	return "RARP";break;
    case 0x809B:	return "Ethertalk";break;
    case 0x80F3:	return "AARP";break;
    case 0x8100:	return "VLAN-tagged frame";break;
    case 0x8102:	return "SLPP";break;
    case 0x8103:	return "VLACP";break;
    case 0x8137:	return "IPX";break;
    case 0x8204:	return "QNX Qnet";break;
    case 0x86DD:	return "IPv6";break;
    case 0x8808:	return "Ethernet flow control";break;
    case 0x8809:	return "Ethernet Slow Protocols";break;
    case 0x8819:	return "CobraNet";break;
    case 0x8847:	return "MPLS unicast";break;
    case 0x8848:	return "MPLS multicast";break;
    case 0x8863:	return "PPPoE Discovery Stage";break;
    case 0x8864:	return "PPPoE Session Stage";break;
    case 0x887B:	return "HomePlug 1.0 MME";break;
    case 0x888E:	return "EAP over LAN";break;
    case 0x8892:	return "PROFINET Protocol";break;
    case 0x889A:	return "HyperSCSI";break;
    case 0x88A2:	return "ATA over Ethernet";break;
    case 0x88A4:	return "EtherCAT Protocol";break;
    case 0x88A8:	return "(S-Tag) on Q-in-Q tunnel.";break;
    case 0x88AB:	return "Ethernet Powerlink";break;
    case 0x88B8:	return "GOOSE";break;
    case 0x88B9:	return "GSE  Management Services";break;
    case 0x88BA:	return "SV ";break;
    case 0x88BF:	return "MikroTik RoMON";break;
    case 0x88CC:	return "LLDP";break;
    case 0x88CD:	return "SERCOS III";break;
    case 0x88E1:	return "HomePlug Green PHY";break;
    case 0x88E3:	return "IEC62439-2";break;
    case 0x88E5:	return "MACsec";break;
    case 0x88E7:	return "PBB";break;
    case 0x88F7:	return "PTP";break;
    case 0x88F8:	return "NC-SI";break;
    case 0x88FB:	return "PRP";break;
    case 0x8902:	return "CFM / OAM";break;
    case 0x8906:	return "FCoE";break;
    case 0x8914:	return "FCoE Initialization Protocol";break;
    case 0x8915:	return "RoCE";break;
    case 0x891D:	return "TTE";break;
    case 0x893a:	return "1905.1 IEEE Protocol";break;
    case 0x892F:	return "HSR";break;
    case 0x9000:	return "Ethernet Configuration Testing Protocol";break;
    case 0xF1C1:	return "Redundancy Tag";break;
    default: return "ETH";
    }
}
my_packge* eth_handler(const unsigned char* data,Ui::MainWindow *ui)
{
    eth_header *header = (eth_header*) data;
    u_short type = ntohs(header->type);

    my_packge *packge;

    if(ui!=nullptr){
        QTreeWidgetItem* item = get_tree_item("Ethernet II, Src: "+format_mac(header->source)+", Dst: "+format_mac(header->destination));
        ui->treeWidget->addTopLevelItem(item);
        item->addChild(get_tree_item("Destination: "+format_mac(header->destination)));
        item->addChild(get_tree_item("Source: "+format_mac(header->source)));
        item->addChild(get_tree_item("Type: "+format_eth_type(type)));
    }

    switch (type) {
        case 0x0800:
            packge = ip_handler(data,ui);
            break;
        case 0x0806:
            packge = arp_handler(data,ui);
            break;
        default:
            packge = new my_packge();
            packge->proto = "ETH";
            packge->source = format_mac(header->source);
            packge->destination = format_mac(header->destination);
    }
    return packge;
}





my_packge *ip_handler(const unsigned char *data,Ui::MainWindow *ui)
{
    ip_header *header = (ip_header*)(data+14);
    my_packge* packge;
    char proto =  header->proto;

    if(ui!=nullptr){
        QTreeWidgetItem* item = get_tree_item("Internet Protocol Version 4, Src: "+format_ip(header->src_ip_addr)+", Dst: "+format_ip(header->des_ip_addr));
        ui->treeWidget->addTopLevelItem(item);

        item->addChild(get_tree_item("Version: "+QString::number(header->ver_len>>4)));
        item->addChild(get_tree_item("Header Length: "+QString::number(header->ver_len&0xff)));
        item->addChild(get_tree_item("Service Type: 0x"+QString("%1").arg(header->service_type,2,16,QLatin1Char('0'))));
        item->addChild(get_tree_item("Total Length: "+ QString::number(ntohs(header->totle_len))));
        item->addChild(get_tree_item("Identification: "+QString::number(ntohs(header->identification))));
    }

    switch (proto) {
        case 1:
            packge = icmp_handler(data,ui);
            break;
        case 6:
            packge = tcp_handler(data,ui);
            break;
        case 17:
            packge = udp_handler(data,ui);
            break;
        default:
            packge= new my_packge();
            packge->proto = "IP";
            break;
    }
    packge->source = format_ip(header->src_ip_addr);
    packge->destination = format_ip(header->des_ip_addr);

    return packge;
}

my_packge *tcp_handler(const unsigned char *data, Ui::MainWindow *ui)
{
    my_packge * pack = new my_packge();
    pack->proto = "TCP";

    //tcp 添加info信息
    //1.分析端口
    tcp_header * header = (tcp_header*)(data+14+20);
    QString src_port = QString::number(ntohs(header->source_port));
    QString des_port = QString::number(ntohs(header->dest_port));
    QString seq = QString::number(ntohl(header->seq));
    QString ack = QString::number(ntohl(header->ack));
    QString win_size = QString::number(ntohs(header->window_size));

    //treeView分析
    if(ui!=nullptr){
        QTreeWidgetItem* item = get_tree_item("Transmission Control Protocol, Src Port: "+src_port
                                              +", Dst Port: "+des_port
                                              + ", Seq: "+ seq
                                              + ", Ack: "+ack
                                              );
        ui->treeWidget->addTopLevelItem(item);
        item->addChild(get_tree_item("Source Port: "+src_port));
        item->addChild(get_tree_item("Destination Port: "+des_port));
        item->addChild(get_tree_item("Sequence Number: "+seq));
        item->addChild(get_tree_item("Acknowledgment Number: "+ack));
    }



    pack->info+=QString("%1 -> %2").arg(src_port).arg(des_port);
    //2.分析Flags
//    pack->info+="[";
//    u_short flags = ntohs(header->flags);
//    int ack = ((flags&16) ==16);
//    int syn = ((flags&2)==2);
//    if(ack)pack->info+="ACK";
//    if(syn)pack->info+=", SYN";
//    pack->info+="]";

    //3.分析Seq，Ack，Win, Len
    pack->info+=QString(" Seq=%1").arg(seq);
    pack->info+=QString(" Ack=%1").arg(ack);
    pack->info+=QString(" Win=%1").arg(win_size);


    return pack;
}

my_packge *icmp_handler(const unsigned char *data, Ui::MainWindow *ui)
{
    my_packge * pack = new my_packge();
    pack->proto = "ICMP";
    icmp_header * header = (icmp_header*)(data+14+20); 
    u_char type = header->type;
    u_char code = header->code;
    QString checksum=QString::number(ntohs(header->checksum));


    if(ui!=nullptr){
        QTreeWidgetItem* item = get_tree_item("Internet Control Message Protocol");
        ui->treeWidget->addTopLevelItem(item);
        item->addChild(get_tree_item("Type: "+QString::number(type)));
        item->addChild(get_tree_item("Code: "+QString::number(code)));
        item->addChild(get_tree_item("Checksum: "+checksum));
    }


    pack->info+= "Type: "+QString::number(type)+", Code: "+QString::number(code);
    return pack;
}

my_packge *udp_handler(const unsigned char *data, Ui::MainWindow *ui)
{
    my_packge * pack = new my_packge();
    pack->proto = "UDP";

    udp_header * header = (udp_header*)(data+14+20);
    QString src_port = QString::number(ntohs(header->src_port));
    QString des_port = QString::number(ntohs(header->des_port));
    QString len = QString::number(ntohs(header->len));
    QString checksum = QString("0x%1").arg(ntohs(header->checksum),4,16,QLatin1Char('0'));

    if(ui!=nullptr){
        QTreeWidgetItem* item = get_tree_item("User Datagram Protocol, Src Port: "+src_port+", Dst Port: "+des_port);
        ui->treeWidget->addTopLevelItem(item);
        item->addChild(get_tree_item("Source Port: "+src_port));
        item->addChild(get_tree_item("Destination Port: "+des_port));
        item->addChild(get_tree_item("Length: "+len));
        item->addChild(get_tree_item("Checksum: "+checksum));
    }


    //udp 添加info信息
    //1.分析端口
    pack->info+=QString("%1 -> %2 Len=%3").arg(src_port).arg(des_port).arg(len);

    return pack;
}

my_packge *arp_handler(const unsigned char *data, Ui::MainWindow *ui)
{
    my_packge * pack = new my_packge();
    arp_header* header = (arp_header*)(data+14);
    pack->proto = "ARP";
    pack->source=format_mac(header->src_mac_addr);
    pack->destination = format_mac(header->des_mac_addr);

    if(ntohs(header->op_code)==1){
        //request
        pack->info += QString("Who has %1? Tell %2")
                .arg(format_ip(header->des_ip_addr))
                .arg(format_ip(header->src_ip_addr));
    }else if(ntohs(header->op_code)==2){
        //reply
        pack->info += QString("%1 is at %2")
                .arg(format_ip(header->src_ip_addr))
                .arg(format_mac(header->src_mac_addr));
    }
    return pack;
}
